package com.viu.technology.chat;


import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.SmartLifecycle;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;

@Component
public class ChatServer implements CommandLineRunner {

    private int port=10203;
    private boolean running = false;

    //配置服务端的NIO线程组
    EventLoopGroup bossGroup = new NioEventLoopGroup(8); //用于服务端接收客户端的连接
    EventLoopGroup workerGroup = new NioEventLoopGroup(8);   //用于进行SocketChannel的网络读写

    EventLoopGroup asyncGroup = new DefaultEventLoopGroup(16);


    @Autowired
    ChatServerHandler noticeServerHandler;


    //@PostConstruct
    public void startServer(){
        //用于启动NIO服务端的辅助启动类(降低服务端的开发复杂度)
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)     //配置使用NIO方式
                    //BACKLOG用于构造服务端套接字ServerSocket对象，标识当服务器请求处理线程全满时，
                    //用于临时存放已完成三次握手的请求的队列的最大长度。如果未设置或所设置的值小于1，Java将使用默认值50。
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChildChannelHandler());//IO事件处理类

            //绑定端口，同步等待成功
            ChannelFuture f = b.bind(port).sync();

            //等待服务端监听端口关闭
            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }



    @PreDestroy
    public void destroy() {
        //优雅退出，释放线程池资源
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }

    @Override
    public void run(String... args) throws Exception {
        startServer();
    }


    private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
        @Override
        protected void initChannel(SocketChannel socketChannel) throws Exception {
            ByteBuf delimiter = Unpooled.copiedBuffer("$_".getBytes());
            //当消息达到最大长度后仍然没找到分隔符就抛出ToolLongFrameException以此，防止由于异常码流缺失分隔符导致的内存溢出（netty的可靠性保护）
            //第二个参数就是分隔符缓冲对象
            socketChannel.pipeline().addLast(new DelimiterBasedFrameDecoder(102400,delimiter));
            //socketChannel.pipeline().addLast(new LengthFieldBasedFrameDecoder(65535, 0, 2, 0, 2));
            //socketChannel.pipeline().addLast(new LengthFieldPrepender(2));
            socketChannel.pipeline().addLast(new StringDecoder());
            socketChannel.pipeline().addLast(new StringEncoder());
            //使用线程池优先处理handler的IO任务
            socketChannel.pipeline().addLast(asyncGroup,noticeServerHandler);
            //socketChannel.pipeline().addLast(new IdleStateHandler(4,5, 7, TimeUnit.SECONDS));
            //socketChannel.pipeline().addLast(new HeartbeatServerHandler());
        }
    }





}
